<!DOCTYPE html>
<!--
   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at

       https://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
-->
<html lang="en">
  <head>
    <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
    <title>Programming Selectors in Apache Ant</title>
  </head>

  <body>
    <h2>Programming your own Selectors</h2>

    <h3>Selector Programming API</h3>

    <p>Want to define your own selectors? It's easy!</p>

    <p>First, pick the type of selector that you want to define. There are three types, and a
    recipe for each one follows. Chances are you'll want to work with the first one, Custom
    Selectors.</p>

    <ol>
      <li>Custom Selectors

        <p>This is the category that Apache Ant provides specifically for you to define your own
        Selectors. Anywhere you want to use your selector you use
        the <code>&lt;custom&gt;</code> element and specify the class name of your selector
        within it. See the <a href="selectors.html#customselect">Custom Selectors</a> section of
        the Selector page for details. The <code>&lt;custom&gt;</code> element can be used
        anywhere the core selectors can be used. It can be contained
        within <a href="selectors.html#selectcontainers">Selector Containers</a>, for
        example.</p>

        <p>To create a new Custom Selector, you have to create a class that
        implements <code class="code">org.apache.tools.ant.types.selectors.ExtendFileSelector</code>.
        The easiest way to do that is through the convenience base
        class <code class="code">org.apache.tools.ant.types.selectors.BaseExtendSelector</code>,
        which provides all of the methods for supporting <code>&lt;param&gt;</code> tags. First,
        override the <code class="code">isSelected()</code> method, and optionally
        the <code class="code">verifySettings()</code> method. If your custom selector requires
        parameters to be set, you can also override the <code class="code">setParameters()</code>
        method and interpret the parameters that are passed in any way you like. Several of the core
        selectors demonstrate how to do that because they can also be used as custom selectors.</p>

      <li>Core Selectors

        <p>These are the selectors used by Ant itself. To implement one of these, you will have
        to alter some of the classes contained within Ant.</p>

        <ul>
          <li><p>First, create a class that
            implements <code class="code">org.apache.tools.ant.types.selectors.FileSelector</code>.
            You can either choose to implement all methods yourself from scratch, or you can
            extend <code class="code">org.apache.tools.ant.types.selectors.BaseSelector</code>
            instead, a convenience class that provides reasonable default behaviour for many
            methods.</p>

            <p>There is only one method required.  <code class="code">public boolean isSelected(File
            basedir, String filename, File file)</code> is the real purpose of the whole
            exercise. It returns <q>true</q> or <q>false</q> depending on whether the given file
            should be selected from the list or not.</p>

            <p>If you are
            using <code class="code">org.apache.tools.ant.types.selectors.BaseSelector</code> there
            are also some predefined behaviours you can take advantage of. Any time you encounter a
            problem when setting attributes or adding tags, you can
            call <code class="code">setError(String errmsg)</code> and the class will know that
            there is a problem. Then, at the top of your <code class="code">isSelected()</code>
            method call <code class="code">validate()</code> and a <code>BuildException</code> will
            be thrown with the contents of your error
            message. The <code class="code">validate()</code> method also gives you a last chance to
            check your settings for consistency because it
            calls <code class="code">verifySettings()</code>. Override this method and
            call <code class="code">setError()</code> within it if you detect any problems in how
            your selector is set up.</p>

            <p>You may also want to override <code class="code">toString()</code>.</p></li>

          <li>Put an <code class="code">add()</code> method for your selector
            in <code class="code">org.apache.tools.ant.types.selectors.SelectorContainer</code>.
            This is an interface, so you will also have to add an implementation for the method in
            the classes which implement it,
            namely <code class="code">org.apache.tools.ant.types.AbstractFileSet</code>, <code class="code">org.apache.tools.ant.taskdefs.MatchingTask</code>
            and <code class="code">org.apache.tools.ant.types.selectors.BaseSelectorContainer</code>.
            Once it is in there, it will be available everywhere that core selectors are
            appropriate.</li>
        </ul>

      <li>Selector Containers
        <p>Got an idea for a new Selector Container? Creating a new one is no problem:</p>
        <ul>
          <li>Create a new class that
            implements <code class="code">org.apache.tools.ant.types.selectors.SelectorContainer</code>.
            This will ensure that your new Container can access any new selectors that come
            along. Again, there is a convenience class available for you
            called <code class="code">org.apache.tools.ant.types.selectors.BaseSelectorContainer</code>.</li>
          <li>Implement the <code class="code">public boolean isSelected(String filename, File
            file)</code> method to do the right thing. Chances are you'll want to iterate over the
            selectors under you, so use <code class="code">selectorElements()</code> to get an
            iterator that will do that.</li>
          <li>Again, put an <code class="code">add()</code> method for your container
            in <code class="code">org.apache.tools.ant.types.selectors.SelectorContainer</code> and
            its implementations <code class="code">org.apache.tools.ant.types.AbstractFileSet</code>
            and <code class="code">org.apache.tools.ant.types.selectors.BaseSelectorContainer</code>.</li>
        </ul>
    </ol>

    <h3>Testing Selectors</h3>

    <p>For a robust component (and selectors are (Project)Components) tests are necessary. For
    testing Tasks we use JUnit Tests and Rules&mdash;more
    specific <code class="code">org.apache.tools.ant.BuildFileRule extends
    org.junit.rules.ExternalResource</code>.  Some of its features like configure the (test) project
    by reading its buildfile and execute targets we need for selector tests also. Therefore we use
    that BuildFileRule.  But testing selectors requires some more work: having a set of files,
    instantiate and configure the selector, check the selection work and more. Because we usually
    extend <code class="code">BaseExtendSelector</code> its features have to be tested also
    (e.g. <code class="code">setError()</code>).</p>

    <p>That's why we have a test rule for doing our selector
    tests: <code class="code">org.apache.tools.ant.types.selectors.BaseSelectorRule</code>.</p>

    <p>This class extends ExternalResource and therefore can included in the set of Ant's unit
    tests. It holds an instance of preconfigured BuildFileRule. Configuration is done by parsing
    the <samp>src/etc/testcases/types/selectors.xml</samp>. BaseSelectorRule then gives us
    helper methods for handling multiple selections.</p>

    <p>Because the term "testcase" or "testenvironment" are so often used, this special
    testenvironment got a new name: <em>bed</em>. The setup and cleanup of the bed is all
    handled by the BaseSelectorRule so any test only has to handle the actual test scenarios</p>

    <p>A usual test scenario is:</p>
    <ol>
       <li>instantiate the selector</li>
       <li>configure the selector</li>
       <li>let the selector do some work</li>
       <li>verify the work</li>
    </ol>

    <p>An example test would be:</p>
    <pre>
package org.apache.tools.ant.types.selectors;

public class MySelectorTest {

    @Rule
    public final BaseSelectorRule selectorRule = new BaseSelectorRule();

    @Test
    public void testCase1() {

        // Configure the selector
        MySelector s = new MySelector();
        s.addParam("key1", "value1");
        s.addParam("key2", "value2");
        s.setXX(true);
        s.setYY("a value");

        // do the tests
        assertEquals("FTTTTTTTT", selectorRule.selectionString(s));
    }
}</pre>
    <p>As an example of an error JUnit could log</p>
    <pre>
[junit]     FAILED
[junit] Error for files: <span style="color:blue">.;copy.filterset.filtered;tar/gz/asf-logo.gif.tar.gz</span>
[junit] expected:&lt;<span style="color:blue">FTTTFTTTF...</span>&gt; but was:&lt;TTTTTTTTT...&gt;
[junit] junit.framework.ComparisonFailure: Error for files: .;copy.filterset.filtered;tar/gz/asf-logo.gif.tar.gz
[junit] expected:&lt;FTTTFTTTF...&gt; but was:&lt;TTTTTTTTT...&gt;
[junit]     at junit.framework.Assert.assertEquals(Assert.java:81)
[junit]     at org.apache.tools.ant.types.selectors.BaseSelectorTest.performTest(BaseSelectorTest.java:194)</pre>

    <p>Described above the test class should provide a <code class="code">getInstance()</code>
    method. But that isn't used here. The used <code class="code">getSelector()</code> method is
    implemented in the base class and gives an instance of an Ant Project to the selector. This is
    usually done inside normal build file runs, but not inside this special environment, so this
    method gives the selector the ability to use its own Project object
    (<code class="code">getProject()</code>), for example for logging.</p>

    <h3>Logging</h3>

    <p>During development and maybe later you sometimes need the output of information.  Therefore
    Logging is needed. Because the selector extends BaseExtendSelector or directly BaseSelector it
    is an Ant <code class="code">DataType</code> and therefore
    a <code class="code">ProjectComponent</code>.<br/>  That means that you have access to the
    project object and its logging capability.  <code class="code">ProjectComponent</code> itself
    provides <code class="code">log()</code> methods which will do the access to the project
    instance. Logging is therefore done simply with:</p>
    <pre>log("message");</pre>
    <p>or</p>
    <pre>log("message", loglevel);</pre>
    <p>where the <code>loglevel</code> is one of the values</p>
    <ul>
      <li><code class="code">org.apache.tools.ant.Project.MSG_ERR</code></li>
      <li><code class="code">org.apache.tools.ant.Project.MSG_WARN</code></li>
      <li><code class="code">org.apache.tools.ant.Project.MSG_INFO</code> (default)</li>
      <li><code class="code">org.apache.tools.ant.Project.MSG_VERBOSE</code></li>
      <li><code class="code">org.apache.tools.ant.Project.MSG_DEBUG</code></li>
    </ul>

  </body>
</html>
